<?xml version="1.0" encoding="UTF-8"?>

<!-- This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<!DOCTYPE bindings SYSTEM "chrome://browser/locale/statusbar/statusbar-prefs.dtd">

<bindings id="status4evar-prefs-bindings"
          xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns:xbl="http://www.mozilla.org/xbl">

  <binding id="css-bg-editor">
    <content sizetopopup="pref">
      <xul:vbox flex="1">
        <xul:deck anonid="css-bg-editor-deck" flex="1">
          <xul:vbox>
            <xul:hbox align="center">
              <xul:label xbl:inherits="disabled">&status4evar.editor.css.color.label;</xul:label>
              <xul:colorpicker anonid="css-bg-editor-color" type="button" onchange="this._editor._buildCSS();" xbl:inherits="disabled" />
            </xul:hbox>

            <xul:hbox align="center">
              <xul:label xbl:inherits="disabled">&status4evar.editor.css.image.label;</xul:label>
              <xul:textbox anonid="css-bg-editor-image" readonly="true" flex="1" xbl:inherits="disabled" />
              <xul:button anonid="css-bg-editor-image-browse" label="&status4evar.option.browse;" oncommand="this._editor._imageBrowse();" xbl:inherits="disabled" />
            </xul:hbox>
            <xul:hbox align="center" pack="end">
              <xul:button anonid="css-bg-editor-image-clear" label="&status4evar.option.clear;" oncommand="this._editor._imageClear();" xbl:inherits="disabled=no-image" />
            </xul:hbox>

            <xul:hbox>
              <xul:groupbox pack="center">
                <xul:caption label="" />
                <xul:hbox flex="1" align="center">
                  <xul:label>X</xul:label>
                </xul:hbox>
                <xul:separator class="groove" orient="horizontal" />
                <xul:hbox flex="1" align="center">
                  <xul:label>Y</xul:label>
                </xul:hbox>
              </xul:groupbox>

              <xul:groupbox>
                <xul:caption label="&status4evar.editor.css.image.repeat;" xbl:inherits="disabled=no-image" />
                <xul:menulist anonid="css-bg-editor-image-repeat-x" sizetopopup="always" onselect="this._editor._buildCSS();" xbl:inherits="disabled=no-image">
                  <xul:menupopup>
                    <xul:menuitem label="&status4evar.option.no-repeat;" value="no-repeat" />
                    <xul:menuitem label="&status4evar.option.repeat;"    value="repeat" />
<!--
                    <xul:menuitem label="&status4evar.option.space;"     value="space" />
                    <xul:menuitem label="&status4evar.option.round;"     value="round" />
-->
                  </xul:menupopup>
                </xul:menulist>
                <xul:separator class="groove" orient="horizontal" />
                <xul:menulist anonid="css-bg-editor-image-repeat-y" sizetopopup="always" onselect="this._editor._buildCSS();" xbl:inherits="disabled=no-image">
                  <xul:menupopup>
                    <xul:menuitem label="&status4evar.option.no-repeat;" value="no-repeat" />
                    <xul:menuitem label="&status4evar.option.repeat;"    value="repeat" />
<!--
                    <xul:menuitem label="&status4evar.option.space;"     value="space" />
                    <xul:menuitem label="&status4evar.option.round;"     value="round" />
-->
                  </xul:menupopup>
                </xul:menulist>
              </xul:groupbox>

              <xul:groupbox>
                <xul:caption label="&status4evar.editor.css.image.position;" xbl:inherits="disabled=no-image" />
                <xul:menulist anonid="css-bg-editor-image-position-x" sizetopopup="always" onselect="this._editor._updatePositionX();" xbl:inherits="disabled=no-image">
                  <xul:menupopup>
                      <xul:menuitem label="&status4evar.option.left;"   value="left" />
                      <xul:menuitem label="&status4evar.option.center;" value="center" />
                      <xul:menuitem label="&status4evar.option.right;"  value="right" />
                      <xul:menuitem label="&status4evar.option.offset;" value="offset" />
                  </xul:menupopup>
                </xul:menulist>
                <xul:separator class="groove" orient="horizontal" />
                <xul:menulist anonid="css-bg-editor-image-position-y" sizetopopup="always" onselect="this._editor._updatePositionY();" xbl:inherits="disabled=no-image">
                  <xul:menupopup>
                      <xul:menuitem label="&status4evar.option.top;"    value="top" />
                      <xul:menuitem label="&status4evar.option.center;" value="center" />
                      <xul:menuitem label="&status4evar.option.bottom;" value="bottom" />
                      <xul:menuitem label="&status4evar.option.offset;" value="offset" />
                  </xul:menupopup>
                </xul:menulist>
              </xul:groupbox>

              <xul:groupbox>
                <xul:caption label="&status4evar.editor.css.image.offset;" xbl:inherits="disabled=no-image" />
                <xul:hbox>
                  <xul:textbox anonid="css-bg-editor-image-offset-x" type="number" size="4" min="-65535" onchange="this._editor._buildCSS();" />
                  <xul:menulist anonid="css-bg-editor-image-offset-unit-x" sizetopopup="always" onselect="this._editor._buildCSS();">
                    <xul:menupopup>
                        <xul:menuitem label="%" value="%" />
                        <xul:menuitem label="px" value="px" />
                        <xul:menuitem label="em" value="em" />
                        <xul:menuitem label="in" value="in" />
                        <xul:menuitem label="cm" value="cm" />
                        <xul:menuitem label="mm" value="mm" />
                        <xul:menuitem label="pt" value="pt" />
                        <xul:menuitem label="pc" value="pc" />
                    </xul:menupopup>
                  </xul:menulist>
                </xul:hbox>
                <xul:separator class="groove" orient="horizontal" />
                <xul:hbox>
                  <xul:textbox anonid="css-bg-editor-image-offset-y" type="number" size="4" min="-65535" onchange="this._editor._buildCSS();" />
                  <xul:menulist anonid="css-bg-editor-image-offset-unit-y" sizetopopup="always" onselect="this._editor._buildCSS();">
                    <xul:menupopup>
                        <xul:menuitem label="%" value="%" />
                        <xul:menuitem label="px" value="px" />
                        <xul:menuitem label="em" value="em" />
                        <xul:menuitem label="in" value="in" />
                        <xul:menuitem label="cm" value="cm" />
                        <xul:menuitem label="mm" value="mm" />
                        <xul:menuitem label="pt" value="pt" />
                        <xul:menuitem label="pc" value="pc" />
                    </xul:menupopup>
                  </xul:menulist>
                </xul:hbox>
              </xul:groupbox>
            </xul:hbox>
          </xul:vbox>

          <xul:textbox anonid="css-bg-editor-css-text" multiline="true" rows="6" xbl:inherits="disabled" />
        </xul:deck>
      </xul:vbox>

      <xul:hbox align="center" pack="end">
        <children includes="progressmeter|toolbox" />
        <xul:label xbl:inherits="disabled">&status4evar.editor.label;</xul:label>
        <xul:menulist anonid="css-bg-editor-mode-menu" sizetopopup="always" onselect="this._editor._updateMode();" xbl:inherits="disabled">
          <xul:menupopup>
            <xul:menuitem label="&status4evar.option.simple;" />
            <xul:menuitem label="&status4evar.option.advanced;" />
          </xul:menupopup>
        </xul:menulist>
      </xul:hbox>
    </content>

    <implementation>
      <constructor><![CDATA[
        [
          "_editorColor",
          "_editorImageBrowse",
          "_editorImageClear",
          "_editorImageRepeatX",
          "_editorImageRepeatY",
          "_editorImagePositionX",
          "_editorImagePositionY",
          "_editorImageOffsetX",
          "_editorImageOffsetY",
          "_editorImageOffsetUnitX",
          "_editorImageOffsetUnitY",
          "_editorMode"
        ].forEach(function(prop)
        {
          this[prop]._editor = this;
        }, this);

        this.setAdvanced(true, false);
      ]]></constructor>

      <destructor><![CDATA[
      ]]></destructor>

      <field name="_disableBuildCSS"><![CDATA[
        true
      ]]></field>

      <field name="_editorColor" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-color");
      ]]></field>

      <field name="_editorCSS" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-css-text");
      ]]></field>

      <field name="_editorDeck" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-deck");
      ]]></field>

      <field name="_editorImage" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image");
      ]]></field>

      <field name="_editorImageBrowse" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-browse");
      ]]></field>

      <field name="_editorImageClear" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-clear");
      ]]></field>

      <field name="_editorImageRepeatX" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-repeat-x");
      ]]></field>

      <field name="_editorImageRepeatY" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-repeat-y");
      ]]></field>

      <field name="_editorImagePositionX" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-position-x");
      ]]></field>

      <field name="_editorImagePositionY" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-position-y");
      ]]></field>

      <field name="_editorImageOffsetX" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-x");
      ]]></field>

      <field name="_editorImageOffsetY" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-y");
      ]]></field>

      <field name="_editorImageOffsetUnitX" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-unit-x");
      ]]></field>

      <field name="_editorImageOffsetUnitY" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-image-offset-unit-y");
      ]]></field>

      <field name="_editorMode" readonly="true"><![CDATA[
        document.getAnonymousElementByAttribute(this, "anonid", "css-bg-editor-mode-menu");
      ]]></field>

      <field name="_initialized"><![CDATA[
        false
      ]]></field>

      <field name="_reRGB" readonly="true"><![CDATA[
        /^rgb\((\d+), (\d+), (\d+)\)$/
      ]]></field>

      <field name="_reURL" readonly="true"><![CDATA[
        /^url\(\s*['"]?(.+?)['"]?\s*\)$/
      ]]></field>

      <field name="_reBgPosition" readonly="true"><![CDATA[
        /^(left|center|right)? ?(-?\d+[^\s\d]+)? ?(top|center|bottom)? ?(-?\d+[^\s\d]+)?$/
      ]]></field>

      <field name="_reCSSUnit" readonly="true"><![CDATA[
        /^(-?\d+)([^\s\d]+)$/
      ]]></field>

      <field name="_strings" readonly="true"><![CDATA[
        document.getElementById("bundle_status4evar");
      ]]></field>

      <property name="value">
        <getter><![CDATA[
          return this._editorCSS.value;
        ]]></getter>
        <setter><![CDATA[
          this._editorCSS.value = val;

          if(!this._initialized)
          {
            this.setAdvanced(false, false);
            this._initialized = true;
          }

          return val;
        ]]></setter>
      </property>

      <property name="disabled">
        <getter><![CDATA[
          return this.getAttribute("disabled") == "true";
        ]]></getter>
        <setter><![CDATA[
          if(val)
          { 
            this.setAttribute("disabled", "true");
          }
          else
          {
            this.removeAttribute("disabled");
          }

          this._updateImageControllDisable();

          return val;
        ]]></setter>
      </property>

      <method name="setAdvanced">
        <parameter name="aVal"/>
        <parameter name="aPrompt"/>
        <body><![CDATA[
          if(!aVal)
          {
            let success = this._parseCSS();
            if(!success)
            {
              let result = aPrompt && Services.prompt.confirm(window,
                                                              this._strings.getString("simpleEditorTitle"),
                                                              this._strings.getString("simpleEditorMessage"));
              if(result)
              {  // Continue to simple mode
                this._buildCSS();
              }
              else
              {  // Stay on advanced mode
                aVal = true;
              }
            }
          }

          this._disableBuildCSS = aVal;
          this._editorDeck.selectedIndex = ((aVal) ? 1 : 0);
          this._editorMode.selectedIndex = ((aVal) ? 1 : 0);
        ]]></body>
      </method>

      <method name="_buildCSS">
        <body><![CDATA[
          if(this._disableBuildCSS)
          {
            return;
          }

          let cssVal = this._editorColor.color;
          let imgVal = this._editorImage.value;
          if(imgVal)
          {
            cssVal += " url(\"" + imgVal + "\")";

            //
            // Print the background repeat
            //
            let bgRX = this._editorImageRepeatX.value;
            let bgRY = this._editorImageRepeatY.value;
            if(bgRX == "repeat" && bgRY == "no-repeat")
            {
              cssVal += " repeat-x";
            }
            else if(bgRX == "no-repeat" && bgRY == "repeat")
            {
              cssVal += " repeat-y";
            }
            else
            {
              cssVal += " " + bgRX;
              if(bgRX != bgRY)
              {
                cssVal += " " + bgRY;
              }
            }

            //
            // Print the background position
            //
            let bgPX = this._editorImagePositionX.value;
            let bgPOX = this._editorImageOffsetX.value;
            if(bgPX != "offset")
            {
              cssVal += " " + bgPX;
            }
            else
            {
              cssVal += " " + bgPOX + this._editorImageOffsetUnitX.value;
            }

            let bgPY = this._editorImagePositionY.value;
            let bgPOY = this._editorImageOffsetY.value;
            if(bgPY != "offset")
            {
              cssVal += " " + bgPY;
            }
            else
            {
              cssVal += " " + bgPOY + this._editorImageOffsetUnitY.value;
            }
          }

          this._editorCSS.value = cssVal;

          let event = document.createEvent("Event");
          event.initEvent("change", true, true);
          this._editorCSS.dispatchEvent(event);
        ]]></body>
      </method>

      <method name="_parseCSS">
        <body><![CDATA[
          let retVal = true;

          let cssParser = document.createElement("div");
          cssParser.style.background = this._editorCSS.value;
          if(!cssParser.style.background)
          {
            Components.utils.reportError("Error parsing background CSS rule: " + this._editorCSS.value);
            cssParser.style.background = "#33FF33";
            retVal = false;
          }

          //
          // Parse the background color
          //
          let bgC = cssParser.style.backgroundColor;
          if(this._reRGB.test(bgC))
          {
            let digits = this._reRGB.exec(bgC);

            let red = parseInt(digits[1]);
            let green = parseInt(digits[2]);
            let blue = parseInt(digits[3]);

            let rgb = blue | (green << 8) | (red << 16);
            bgC =  "#" + rgb.toString(16);
          }
          else
          {
            Components.utils.reportError("Error parsing background-color value: " + bgC);
            bgC = "#33FF33";
            retVal = false;
          }

          //
          // Parse the background image
          //
          let bgI = cssParser.style.backgroundImage;
          if(bgI != "none" && !this._reURL.test(bgI))
          {
            Components.utils.reportError("Error parsing background-image value: " + bgI);
            bgI = "none";
            retVal = false;
          }
          bgI = ((bgI != "none") ? this._reURL.exec(bgI)[1].trim() : "");

          //
          // Parse the background repeat
          //
          let bgR = cssParser.style.backgroundRepeat.split(" ");
          let bgRX = bgR[0];
          if(bgRX == "repeat-x")
          {
            bgRX = "repeat";
          }
          else if(bgRX == "repeat-y")
          {
            bgRX = "no-repeat";
          }

          let bgRY = bgR[bgR.length - 1];
          if(bgRY == "repeat-x")
          {
            bgRY = "no-repeat";
          }
          else if(bgRY == "repeat-y")
          {
            bgRY = "repeat";
          }

          //
          // Parse the background position
          //
          let bgP = cssParser.style.backgroundPosition;
          let bgPParts = this._reBgPosition.exec(bgP);
          let bgPValues = new Array();
          for(let i = 1; i <= 4; i++)
          {
            if(bgPParts[i])
            {
              bgPValues.push({
                "value": bgPParts[i],
                "group": i
              });
            }
          }

          if(bgPValues.length == 1)
          {
            bgPValues.splice(((bgPValues[0].group == 2) ? 0 : 1), 0, {
              "value": "center",
              "group": ((bgPValues[0].group == 2) ? 0 : 2)
            });
          }

          if(bgPValues.length == 2 && bgPValues[1].group == 2)
          {
            bgPValues[1].group = 4;
          }

          for(let i = 0; i < 4; i++)
          {
            let group = (i + 1);
            if(bgPValues[i] != undefined && bgPValues[i].group == group)
            {
              continue;
            }

            let tmp = "0px";
            switch(i)
            {
              case 0:
                tmp = "offset";
                break;
              case 2:
                tmp = "offset";
                break;
            }

            bgPValues.splice(i, 0, {
              "value": tmp,
              "group": group
            });
          }

          let bgPOXParts = this._reCSSUnit.exec(bgPValues[1].value);
          let bgPOYParts = this._reCSSUnit.exec(bgPValues[3].value);

          //
          // Parse the background size
          //

          //
          // Initialize the UI
          //
          let disableBuildCSS = this._disableBuildCSS;
          this._disableBuildCSS = true;

          this._editorColor.color = bgC;
          this._editorImage.value = bgI;
          this._editorImageOffsetX.value = bgPOXParts[1];
          this._editorImageOffsetY.value = bgPOYParts[1];

          [
            [this._editorImageRepeatX,  bgRX,      "repeat",  "repeat X"],
            [this._editorImageRepeatY,  bgRY,      "repeat",  "repeat Y"],
            [this._editorImagePositionX,  bgPValues[0].value,  "left",    "position X"],
            [this._editorImagePositionY,  bgPValues[2].value,  "top",    "position Y"],
            [this._editorImageOffsetUnitX,  bgPOXParts[2],    "px",    "offset X unit"],
            [this._editorImageOffsetUnitY,  bgPOYParts[2],    "px",    "offset Y unit"]
          ].forEach(function(info)
          {
            if(!this._setSelectedItemSafe(info[0], info[1], info[2]))
            {
              Components.utils.reportError("Error setting " + info[3] + " to " + info[1]);
              retVal = false;
            }
          }, this);

          this._updateImageControllDisable();

          this._disableBuildCSS = disableBuildCSS;

          return retVal;
        ]]></body>
      </method>

      <method name="_imageBrowse">
        <body><![CDATA[
          let nsIFilePicker = Components.interfaces.nsIFilePicker;
          let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
          filePicker.init(window, this._strings.getString("imageSelectTitle"), nsIFilePicker.modeOpen);
          filePicker.appendFilters(nsIFilePicker.filterImages);

          let res = filePicker.show();
          if(res == nsIFilePicker.returnOK)
          {
            this._editorImage.value =  Services.io.newFileURI(filePicker.file).spec;
            this._updateImageControllDisable();
            this._buildCSS();
          }
        ]]></body>
      </method>

      <method name="_imageClear">
        <body><![CDATA[
          this._editorImage.value =  "";
          this._editorImageRepeatX.value = "repeat";
          this._editorImageRepeatY.value = "repeat";
          this._editorImagePositionX.value = "left";
          this._editorImagePositionY.value = "top";
          this._editorImageOffsetX.value = 0;
          this._editorImageOffsetY.value = 0;
          this._editorImageOffsetUnitX.value = "px";
          this._editorImageOffsetUnitY.value = "px";
          this._updateImageControllDisable();
          this._buildCSS();
        ]]></body>
      </method>

      <method name="_processEvent">
        <parameter name="event"/>
        <body><![CDATA[
          if(!("css-bg-editor-css-text" == event.originalTarget.getAttribute("anonid")
          || "css-bg-editor-css-text" == document.getBindingParent(event.originalTarget).getAttribute("anonid")))
          {
            event.stopPropagation();
          }

          //Components.utils.reportError("Editor event " + event.type + " on " + event.originalTarget.tagName + "::" + event.originalTarget.getAttribute("anonid"));
        ]]></body>
      </method>

      <method name="_setSelectedItemSafe">
        <parameter name="aElement"/>
        <parameter name="aValue"/>
        <parameter name="aDefault"/>
        <body><![CDATA[
          aElement.value = aValue;
          if(!aElement.selectedItem || aElement.selectedItem.value != aValue)
          {
            aElement.value = aDefault;
            return false;
          }
          return true;
        ]]></body>
      </method>

      <method name="_updateImageControllDisable">
        <body><![CDATA[
          if(this.disabled || !this._editorImage.value)
          {
            this.setAttribute("no-image", "true");
            this._updatePositionOffsetXDisabled(true);
            this._updatePositionOffsetYDisabled(true);
          }
          else
          {
            this.removeAttribute("no-image");
            this._updatePositionOffsetXDisabled(false);
            this._updatePositionOffsetYDisabled(false);
          }
        ]]></body>
      </method>

      <method name="_updateMode">
        <body><![CDATA[
          if(this._editorMode.selectedIndex == this._editorDeck.selectedIndex)
          {
            return;
          }

          this.setAdvanced(((this._editorMode.selectedIndex == 1) ? true : false), true);
        ]]></body>
      </method>

      <method name="_updatePositionOffsetXDisabled">
        <parameter name="aVal"/>
        <body><![CDATA[
          let bgPX = this._editorImagePositionX.value;
          let disableOffsetX = aVal || (bgPX != "offset");// || bgPX == "center");
          this._editorImageOffsetX.disabled = disableOffsetX;
          this._editorImageOffsetUnitX.disabled = disableOffsetX;
        ]]></body>
      </method>

      <method name="_updatePositionOffsetYDisabled">
        <parameter name="aVal"/>
        <body><![CDATA[
          let bgPY = this._editorImagePositionY.value;
          var disableOffsetY = aVal || (bgPY != "offset");// || bgPY == "center");
          this._editorImageOffsetY.disabled = disableOffsetY;
          this._editorImageOffsetUnitY.disabled = disableOffsetY;
        ]]></body>
      </method>

      <method name="_updatePositionX">
        <body><![CDATA[
          this._updatePositionOffsetXDisabled(false);
          this._buildCSS();
        ]]></body>
      </method>

      <method name="_updatePositionY">
        <body><![CDATA[
          this._updatePositionOffsetYDisabled(false);
          this._buildCSS();
        ]]></body>
      </method>
    </implementation>

    <handlers>
      <handler event="command"><![CDATA[
        this._processEvent(event);
      ]]></handler>

      <handler event="change"><![CDATA[
        this._processEvent(event);
      ]]></handler>

      <handler event="input"><![CDATA[
        this._processEvent(event);
      ]]></handler>

      <handler event="select"><![CDATA[
        this._processEvent(event);
      ]]></handler>
    </handlers>
  </binding>
</bindings>

